"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = void 0;
var _vue = require("vue");
var _ui = require("../../ui");
var _vn = require("../../ui/src/vn");
var _dom = require("../..//ui/src/dom");
var _utils = require("../..//ui/src/utils");
var _log = require("../../ui/src/log");
var _xeUtils = _interopRequireDefault(require("xe-utils"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var _default = exports.default = (0, _vue.defineComponent)({
  name: 'VxeTabs',
  props: {
    modelValue: [String, Number, Boolean],
    options: Array,
    height: [String, Number],
    destroyOnClose: Boolean,
    titleWidth: [String, Number],
    titleAlign: [String, Number],
    type: String,
    showClose: Boolean,
    padding: {
      type: Boolean,
      default: () => (0, _ui.getConfig)().tabs.padding
    },
    trigger: String,
    beforeChangeMethod: Function,
    closeConfig: Object,
    refreshConfig: Object,
    // 已废弃
    beforeCloseMethod: Function
  },
  emits: ['update:modelValue', 'change', 'tab-change', 'tab-change-fail', 'tab-close', 'tab-close-fail', 'tab-click', 'tab-load'],
  setup(props, context) {
    const {
      slots,
      emit
    } = context;
    const xID = _xeUtils.default.uniqueId();
    const $xeParentTabs = (0, _vue.inject)('$xeTabs', null);
    const refElem = (0, _vue.ref)();
    const refHeadWrapperElem = (0, _vue.ref)();
    const reactData = (0, _vue.reactive)({
      staticTabs: [],
      activeName: null,
      initNames: [],
      lintLeft: 0,
      lintWidth: 0,
      isTabOver: false,
      resizeFlag: 1,
      cacheTabMaps: {}
    });
    const internalData = {
      slTimeout: undefined
    };
    const refMaps = {
      refElem
    };
    const computeCloseOpts = (0, _vue.computed)(() => {
      return Object.assign({}, (0, _ui.getConfig)().tabs.closeConfig, props.closeConfig);
    });
    const computeRefreshOpts = (0, _vue.computed)(() => {
      return Object.assign({}, (0, _ui.getConfig)().tabs.refreshConfig, props.refreshConfig);
    });
    const computeTabOptions = (0, _vue.computed)(() => {
      const {
        options
      } = props;
      return (options || []).filter(item => handleFilterTab(item));
    });
    const computeTabStaticOptions = (0, _vue.computed)(() => {
      const {
        staticTabs
      } = reactData;
      return staticTabs.filter(item => handleFilterTab(item));
    });
    const computeMaps = {};
    const $xeTabs = {
      xID,
      props,
      context,
      reactData,
      getRefMaps: () => refMaps,
      getComputeMaps: () => computeMaps
    };
    const handleFilterTab = item => {
      const {
        permissionCode
      } = item;
      if (permissionCode) {
        if (!_ui.permission.checkVisible(permissionCode)) {
          return false;
        }
      }
      return true;
    };
    const callSlot = (slotFunc, params) => {
      if (slotFunc) {
        if (_xeUtils.default.isString(slotFunc)) {
          slotFunc = slots[slotFunc] || null;
        }
        if (_xeUtils.default.isFunction(slotFunc)) {
          return (0, _vn.getSlotVNs)(slotFunc(params));
        }
      }
      return [];
    };
    const updateTabStyle = () => {
      (0, _vue.nextTick)(() => {
        const {
          type
        } = props;
        const {
          activeName
        } = reactData;
        const tabOptions = computeTabOptions.value;
        const tabStaticOptions = computeTabStaticOptions.value;
        const headerWrapperEl = refHeadWrapperElem.value;
        let lintWidth = 0;
        let lintLeft = 0;
        let isOver = false;
        if (headerWrapperEl) {
          const index = _xeUtils.default.findIndexOf(tabStaticOptions.length ? tabStaticOptions : tabOptions, item => item.name === activeName);
          const {
            children,
            scrollWidth,
            clientWidth
          } = headerWrapperEl;
          isOver = scrollWidth !== clientWidth;
          if (index > -1) {
            const tabEl = children[index];
            const tabWidth = tabEl.clientWidth;
            if (type) {
              if (type === 'card') {
                lintWidth = tabWidth + 2;
                lintLeft = tabEl.offsetLeft;
              } else if (type === 'border-card') {
                lintWidth = tabWidth + 2;
                lintLeft = tabEl.offsetLeft - 1;
              }
            } else {
              lintWidth = Math.max(4, Math.floor(tabWidth * 0.6));
              lintLeft = tabEl.offsetLeft + Math.floor((tabWidth - lintWidth) / 2);
            }
          }
        }
        reactData.lintLeft = lintLeft;
        reactData.lintWidth = lintWidth;
        reactData.isTabOver = isOver;
      });
    };
    const dispatchEvent = (type, params, evnt) => {
      emit(type, (0, _ui.createEvent)(evnt, {
        $tabs: $xeTabs
      }, params));
    };
    const addInitName = (name, evnt) => {
      const {
        initNames
      } = reactData;
      if (name && !initNames.includes(name)) {
        dispatchEvent('tab-load', {
          name
        }, evnt);
        initNames.push(name);
        return true;
      }
      return false;
    };
    const initDefaultName = list => {
      let activeName = null;
      const nameMaps = {};
      if (list && list.length) {
        let validVal = false;
        activeName = props.modelValue;
        list.forEach(item => {
          const {
            name,
            preload
          } = item || {};
          if (name) {
            nameMaps[`${name}`] = {
              loading: false
            };
            if (activeName === name) {
              validVal = true;
            }
            if (preload) {
              addInitName(name, null);
            }
          }
        });
        if (!validVal) {
          activeName = list[0].name;
          addInitName(activeName, null);
          emit('update:modelValue', activeName);
        }
      }
      reactData.activeName = activeName;
      reactData.cacheTabMaps = nameMaps;
    };
    const clickEvent = (evnt, item) => {
      const {
        trigger
      } = props;
      const beforeMethod = props.beforeChangeMethod || (0, _ui.getConfig)().tabs.beforeChangeMethod;
      const {
        activeName
      } = reactData;
      const {
        name
      } = item;
      const value = name;
      dispatchEvent('tab-click', {
        name
      }, evnt);
      if (trigger === 'manual') {
        return;
      }
      if (name !== activeName) {
        Promise.resolve(!beforeMethod || beforeMethod({
          $tabs: $xeTabs,
          name,
          oldName: activeName,
          newName: name,
          option: item
        })).then(status => {
          if (status) {
            reactData.activeName = name;
            emit('update:modelValue', value);
            addInitName(name, evnt);
            dispatchEvent('change', {
              value,
              name,
              oldName: activeName,
              newName: name,
              option: item
            }, evnt);
            dispatchEvent('tab-change', {
              value,
              name,
              oldName: activeName,
              newName: name,
              option: item
            }, evnt);
          } else {
            dispatchEvent('tab-change-fail', {
              value,
              name,
              oldName: activeName,
              newName: name,
              option: item
            }, evnt);
          }
        }).catch(() => {
          dispatchEvent('tab-change-fail', {
            value,
            name,
            oldName: activeName,
            newName: name,
            option: item
          }, evnt);
        });
      }
    };
    const handleRefreshTabEvent = (evnt, item) => {
      evnt.stopPropagation();
      const {
        activeName,
        cacheTabMaps
      } = reactData;
      const {
        name
      } = item;
      const refreshOpts = computeRefreshOpts.value;
      const {
        queryMethod
      } = refreshOpts;
      const cacheItem = name ? cacheTabMaps[`${name}`] : null;
      if (cacheItem) {
        if (queryMethod) {
          cacheItem.loading = true;
          Promise.resolve(queryMethod({
            $tabs: $xeTabs,
            value: activeName,
            name,
            option: item
          })).finally(() => {
            cacheItem.loading = false;
          });
        } else {
          (0, _log.errLog)('vxe.error.notFunc', ['refresh-config.queryMethod']);
        }
      }
    };
    const handleCloseTabEvent = (evnt, item, index, list) => {
      evnt.stopPropagation();
      const {
        activeName
      } = reactData;
      const closeOpts = computeCloseOpts.value;
      const beforeMethod = closeOpts.beforeMethod || props.beforeCloseMethod || (0, _ui.getConfig)().tabs.beforeCloseMethod;
      const {
        name
      } = item;
      const value = activeName;
      let nextName = value;
      if (activeName === name) {
        const nextItem = index < list.length - 1 ? list[index + 1] : list[index - 1];
        nextName = nextItem ? nextItem.name : null;
      }
      Promise.resolve(!beforeMethod || beforeMethod({
        $tabs: $xeTabs,
        value,
        name,
        nextName,
        option: item
      })).then(status => {
        if (status) {
          dispatchEvent('tab-close', {
            value,
            name,
            nextName
          }, evnt);
        } else {
          dispatchEvent('tab-close-fail', {
            value,
            name,
            nextName
          }, evnt);
        }
      }).catch(() => {
        dispatchEvent('tab-close-fail', {
          value,
          name,
          nextName
        }, evnt);
      });
    };
    const startScrollAnimation = (offsetPos, offsetSize) => {
      const {
        slTimeout
      } = internalData;
      let offsetLeft = offsetSize;
      let scrollCount = 6;
      let delayNum = 35;
      if (slTimeout) {
        clearTimeout(slTimeout);
        internalData.slTimeout = undefined;
      }
      const scrollAnimate = () => {
        const headerWrapperEl = refHeadWrapperElem.value;
        if (scrollCount > 0) {
          scrollCount--;
          if (headerWrapperEl) {
            const {
              clientWidth,
              scrollWidth,
              scrollLeft
            } = headerWrapperEl;
            offsetLeft = Math.floor(offsetLeft / 2);
            if (offsetPos > 0) {
              if (clientWidth + scrollLeft < scrollWidth) {
                headerWrapperEl.scrollLeft += offsetLeft;
                delayNum -= 4;
                internalData.slTimeout = setTimeout(scrollAnimate, delayNum);
              }
            } else {
              if (scrollLeft > 0) {
                headerWrapperEl.scrollLeft -= offsetLeft;
                delayNum -= 4;
                internalData.slTimeout = setTimeout(scrollAnimate, delayNum);
              }
            }
            updateTabStyle();
          }
        }
      };
      scrollAnimate();
    };
    const handleScrollToLeft = offsetPos => {
      const headerWrapperEl = refHeadWrapperElem.value;
      if (headerWrapperEl) {
        const offsetSize = Math.floor(headerWrapperEl.clientWidth * 0.75);
        startScrollAnimation(offsetPos, offsetSize);
      }
    };
    const scrollLeftEvent = () => {
      handleScrollToLeft(-1);
    };
    const scrollRightEvent = () => {
      handleScrollToLeft(1);
    };
    const scrollToTab = name => {
      const tabOptions = computeTabOptions.value;
      const tabStaticOptions = computeTabStaticOptions.value;
      return (0, _vue.nextTick)().then(() => {
        const headerWrapperEl = refHeadWrapperElem.value;
        if (headerWrapperEl) {
          const index = _xeUtils.default.findIndexOf(tabStaticOptions.length ? tabStaticOptions : tabOptions, item => item.name === name);
          if (index > -1) {
            const {
              scrollLeft,
              clientWidth,
              children
            } = headerWrapperEl;
            const tabEl = children[index];
            if (tabEl) {
              const tabOffsetLeft = tabEl.offsetLeft;
              const tabClientWidth = tabEl.clientWidth;
              // 如果右侧被挡
              const overSize = tabOffsetLeft + tabClientWidth - (scrollLeft + clientWidth);
              if (overSize > 0) {
                headerWrapperEl.scrollLeft += overSize;
              }
              // 如果左侧被挡，优先
              if (tabOffsetLeft < scrollLeft) {
                headerWrapperEl.scrollLeft = tabOffsetLeft;
              }
            }
          }
          updateTabStyle();
        }
      });
    };
    const handlePrevNext = isNext => {
      const {
        activeName
      } = reactData;
      const tabOptions = computeTabOptions.value;
      const tabStaticOptions = computeTabStaticOptions.value;
      const list = tabStaticOptions.length ? tabStaticOptions : tabOptions;
      const index = _xeUtils.default.findIndexOf(list, item => item.name === activeName);
      if (index > -1) {
        let item = null;
        if (isNext) {
          if (index < list.length - 1) {
            item = list[index + 1];
          }
        } else {
          if (index > 0) {
            item = list[index - 1];
          }
        }
        if (item) {
          const name = item.name;
          const value = name;
          reactData.activeName = name;
          emit('update:modelValue', value);
          addInitName(name, null);
        }
      }
      return (0, _vue.nextTick)();
    };
    const tabsMethods = {
      dispatchEvent,
      scrollToTab,
      prev() {
        return handlePrevNext(false);
      },
      next() {
        return handlePrevNext(true);
      },
      prevTab() {
        if (process.env.NODE_ENV === 'development') {
          (0, _log.warnLog)('vxe.error.delFunc', ['prevTab', 'prev']);
        }
        return tabsMethods.prev();
      },
      nextTab() {
        if (process.env.NODE_ENV === 'development') {
          (0, _log.warnLog)('vxe.error.delFunc', ['nextTab', 'next']);
        }
        return tabsMethods.next();
      }
    };
    const tabsPrivateMethods = {};
    Object.assign($xeTabs, tabsMethods, tabsPrivateMethods);
    const renderTabHeader = tabList => {
      const {
        type,
        titleWidth: allTitleWidth,
        titleAlign: allTitleAlign,
        showClose,
        closeConfig,
        refreshConfig
      } = props;
      const {
        activeName,
        lintLeft,
        lintWidth,
        isTabOver,
        cacheTabMaps
      } = reactData;
      const extraSlot = slots.extra;
      const closeOpts = computeCloseOpts.value;
      const closeVisibleMethod = closeOpts.visibleMethod;
      const refreshOpts = computeRefreshOpts.value;
      const refreshVisibleMethod = refreshOpts.visibleMethod;
      return (0, _vue.h)('div', {
        class: 'vxe-tabs-header'
      }, [isTabOver ? (0, _vue.h)('div', {
        class: 'vxe-tabs-header--bar vxe-tabs-header--left-bar',
        onClick: scrollLeftEvent
      }, [(0, _vue.h)('span', {
        class: (0, _ui.getIcon)().TABS_TAB_BUTTON_LEFT
      })]) : (0, _vue.createCommentVNode)(), (0, _vue.h)('div', {
        class: 'vxe-tabs-header--wrapper'
      }, [(0, _vue.h)('div', {
        ref: refHeadWrapperElem,
        class: 'vxe-tabs-header--item-wrapper'
      }, tabList.map((item, index) => {
        const {
          title,
          titleWidth,
          titleAlign,
          icon,
          name,
          slots
        } = item;
        const titleSlot = slots ? slots.title || slots.tab : null;
        const itemWidth = titleWidth || allTitleWidth;
        const itemAlign = titleAlign || allTitleAlign;
        const params = {
          $tabs: $xeTabs,
          value: activeName,
          name,
          option: item
        };
        const isActive = activeName === name;
        const cacheItem = name ? cacheTabMaps[`${name}`] : null;
        const isLoading = cacheItem ? cacheItem.loading : false;
        return (0, _vue.h)('div', {
          key: `${name}`,
          class: ['vxe-tabs-header--item', itemAlign ? `align--${itemAlign}` : '', {
            'is--active': isActive
          }],
          style: itemWidth ? {
            width: (0, _dom.toCssUnit)(itemWidth)
          } : null,
          onClick(evnt) {
            clickEvent(evnt, item);
          }
        }, [(0, _vue.h)('div', {
          class: 'vxe-tabs-header--item-inner'
        }, [(0, _vue.h)('div', {
          class: 'vxe-tabs-header--item-content'
        }, [icon ? (0, _vue.h)('span', {
          class: 'vxe-tabs-header--item-icon'
        }, [(0, _vue.h)('i', {
          class: icon
        })]) : (0, _vue.createCommentVNode)(), (0, _vue.h)('span', {
          class: 'vxe-tabs-header--item-name'
        }, titleSlot ? callSlot(titleSlot, {
          name,
          title
        }) : `${title}`)]), ((0, _utils.isEnableConf)(refreshConfig) || refreshOpts.enabled) && (refreshVisibleMethod ? refreshVisibleMethod(params) : isActive) ? (0, _vue.h)('div', {
          class: 'vxe-tabs-header--refresh-btn',
          onClick(evnt) {
            handleRefreshTabEvent(evnt, item);
          }
        }, [(0, _vue.h)('i', {
          class: isLoading ? (0, _ui.getIcon)().TABS_TAB_REFRESH_LOADING : (0, _ui.getIcon)().TABS_TAB_REFRESH
        })]) : (0, _vue.createCommentVNode)(), (showClose || (0, _utils.isEnableConf)(closeConfig) || closeOpts.enabled) && (!closeVisibleMethod || closeVisibleMethod(params)) ? (0, _vue.h)('div', {
          class: 'vxe-tabs-header--close-btn',
          onClick(evnt) {
            handleCloseTabEvent(evnt, item, index, tabList);
          }
        }, [(0, _vue.h)('i', {
          class: (0, _ui.getIcon)().TABS_TAB_CLOSE
        })]) : (0, _vue.createCommentVNode)()])]);
      }).concat([(0, _vue.h)('span', {
        key: 'line',
        class: `vxe-tabs-header--active-line type--${type || 'default'}`,
        style: {
          left: `${lintLeft}px`,
          width: `${lintWidth}px`
        }
      })]))]), isTabOver ? (0, _vue.h)('div', {
        class: 'vxe-tabs-header--bar vxe-tabs-header--right-bar',
        onClick: scrollRightEvent
      }, [(0, _vue.h)('span', {
        class: (0, _ui.getIcon)().TABS_TAB_BUTTON_RIGHT
      })]) : (0, _vue.createCommentVNode)(), extraSlot ? (0, _vue.h)('div', {
        class: 'vxe-tabs-header--extra'
      }, (0, _vn.getSlotVNs)(extraSlot({}))) : (0, _vue.createCommentVNode)()]);
    };
    const renderTabPane = item => {
      const {
        initNames,
        activeName
      } = reactData;
      const {
        name,
        slots
      } = item;
      const defaultSlot = slots ? slots.default : null;
      return name && initNames.includes(name) ? (0, _vue.h)('div', {
        key: `${name}`,
        class: ['vxe-tabs-pane--item', {
          'is--visible': activeName === name,
          'has--content': !!defaultSlot
        }]
      }, defaultSlot ? callSlot(defaultSlot, {
        name
      }) : []) : (0, _vue.createCommentVNode)();
    };
    const renderTabContent = tabList => {
      const {
        destroyOnClose
      } = props;
      const {
        activeName
      } = reactData;
      const activeDefaultTab = tabList.find(item => item.name === activeName);
      if (destroyOnClose) {
        return [activeDefaultTab ? renderTabPane(activeDefaultTab) : (0, _vue.createCommentVNode)()];
      }
      return tabList.map(item => renderTabPane(item));
    };
    const renderVN = () => {
      const {
        type,
        height,
        padding,
        trigger
      } = props;
      const tabOptions = computeTabOptions.value;
      const tabStaticOptions = computeTabStaticOptions.value;
      const defaultSlot = slots.default;
      const footerSlot = slots.footer;
      const tabList = defaultSlot ? tabStaticOptions : tabOptions;
      return (0, _vue.h)('div', {
        ref: refElem,
        class: ['vxe-tabs', `vxe-tabs--${type || 'default'}`, `trigger--${trigger === 'manual' ? 'trigger' : 'default'}`, {
          'is--padding': padding,
          'is--height': height
        }],
        style: height ? {
          height: (0, _dom.toCssUnit)(height)
        } : null
      }, [(0, _vue.h)('div', {
        class: 'vxe-tabs-slots'
      }, defaultSlot ? defaultSlot({}) : []), renderTabHeader(tabList), (0, _vue.h)('div', {
        class: 'vxe-tabs-pane'
      }, renderTabContent(tabList)), footerSlot ? (0, _vue.h)('div', {
        class: 'vxe-tabs-footer'
      }, callSlot(footerSlot, {})) : (0, _ui.renderEmptyElement)($xeTabs)]);
    };
    (0, _vue.watch)(() => props.modelValue, val => {
      addInitName(val, null);
      reactData.activeName = val;
    });
    (0, _vue.watch)(() => reactData.activeName, val => {
      scrollToTab(val);
      (0, _vue.nextTick)(() => {
        reactData.resizeFlag++;
      });
    });
    const optsFlag = (0, _vue.ref)(0);
    (0, _vue.watch)(() => props.options ? props.options.length : -1, () => {
      optsFlag.value++;
    });
    (0, _vue.watch)(() => props.options, () => {
      optsFlag.value++;
    });
    (0, _vue.watch)(optsFlag, () => {
      initDefaultName(props.options);
      updateTabStyle();
    });
    const stFlag = (0, _vue.ref)(0);
    (0, _vue.watch)(() => reactData.staticTabs ? reactData.staticTabs.length : -1, () => {
      stFlag.value++;
    });
    (0, _vue.watch)(() => reactData.staticTabs, () => {
      stFlag.value++;
    });
    (0, _vue.watch)(stFlag, () => {
      initDefaultName(reactData.staticTabs);
      updateTabStyle();
    });
    if ($xeParentTabs) {
      (0, _vue.watch)(() => $xeParentTabs ? $xeParentTabs.reactData.resizeFlag : null, () => {
        reactData.resizeFlag++;
      });
    }
    (0, _vue.watch)(() => reactData.resizeFlag, () => {
      (0, _vue.nextTick)(() => {
        updateTabStyle();
      });
    });
    (0, _vue.onMounted)(() => {
      _ui.globalEvents.on($xeTabs, 'resize', updateTabStyle);
      updateTabStyle();
    });
    (0, _vue.onUnmounted)(() => {
      _ui.globalEvents.off($xeTabs, 'resize');
    });
    (0, _vue.provide)('$xeTabs', $xeTabs);
    addInitName(props.modelValue, null);
    initDefaultName(reactData.staticTabs.length ? reactData.staticTabs : props.options);
    $xeTabs.renderVN = renderVN;
    return $xeTabs;
  },
  render() {
    return this.renderVN();
  }
});